package
{
	import com.utils.actionList.ActionList;
	import com.utils.actionList.ActionListEvent;
	
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.ProgressEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.utils.Timer;
	
	import game.controllers.initializer.Initializer;
	import game.physic.Input;
	
	public class Controller extends EventDispatcher
	{
		protected var _al:ActionList;
		
		protected var _tmpVars:Object;
		
		public function Controller( scaffold:Sprite )
		{
			super(null);
			
			Ref.controller = this;
			Ref.model      = new Model();
			Ref.view       = new View(scaffold);
			
			_tmpVars = {};
			
			scaffold.addEventListener(Event.ADDED_TO_STAGE, onStart, false, 0, true);
		}
		
		protected function onStart(ev:Event):void
		{
			Ref.view.scaffold.removeEventListener(Event.ADDED_TO_STAGE, onStart );
			
			start();
		}
		
		protected function start():void
		{
			// ejecuta una lista de acciones no-sincronicas linealmente
			_al = new ActionList();
			_al.addEventListener( ActionListEvent.EVT_ACTION_LIST_ERROR,    onInitSequenceError,false, 0, true);
			_al.addEventListener( ActionListEvent.EVT_ACTION_LIST_COMPLETE, onInitSequenceComplete,false, 0, true);
			
			// 1. setup screen
			_al.add( Ref.view,Ref.view.setupScreen );
			
			// 2. init loader 
			_tmpVars.initializer = new Initializer();
			_al.add(_tmpVars.initializer, _tmpVars.initializer.start);
			
			// 3. show init menu
			_al.add(Ref.view, Ref.view.showInitMenu );

			// 4. setup physics enviroment
			_al.add(Ref.model, Ref.model.setupPhysics );

			// 5. reset Game vars
			_al.add(Ref.model, Ref.model.resetGameVariables );
			_al.add(Ref.view, Ref.view.resetGameVariables );

			// 6. setup game scene 
			_al.add(Ref.view, Ref.view.setupGameScene );

			// start
			_al.start();
		}
		
		protected function onInitSequenceError(ev:ActionListEvent):void
		{ 
			_al.removeEventListener( ActionListEvent.EVT_ACTION_LIST_ERROR   , onInitSequenceError);
			_al.removeEventListener( ActionListEvent.EVT_ACTION_LIST_COMPLETE, onInitSequenceComplete);
			_al.clear();
			_al = null;

			_tmpVars = {};
		}

		protected function onInitSequenceComplete(ev:ActionListEvent):void
		{
			_al.removeEventListener( ActionListEvent.EVT_ACTION_LIST_ERROR, onInitSequenceError);
			_al.removeEventListener( ActionListEvent.EVT_ACTION_LIST_COMPLETE,onInitSequenceComplete);
			_al.clear();
			_al = null;
			
			_tmpVars = {};

			trace("onInitSequenceComplete");
			
			// main Loop
			Ref.view.scaffold.addEventListener(Event.ENTER_FRAME, mainLoop);
		}
		
		//  MAIN LOOP ///////////////////////////////////////////////////////////////////////////////
		protected function mainLoop(ev:Event):void
		{
			Ref.view.gameScene.verifyHandState();

			Ref.model.updateGameTime();
			
			processInputValues();
			
			createItem();
			createEnemy();
			
			Ref.model.physic.Update();
			
			processPhysicCollitions();
			
			Ref.view.gameScene.updateEnemyPosition();
			Ref.view.gameScene.updateItemsPosition();
			Ref.view.gameScene.updateHitItemsPosition();
			Ref.view.gameScene.updateHandPosition();

			removeExtraItems();
			Input.update();
		}
		
		protected function processInputValues():void
		{
			// hand position
			var handPosition:Point = Ref.view.gameScene.getHandPosition();
			
			if ( !Ref.view.gameScene.handIsReady ) return;
			
			if ( Input.mouseReleased )
			{
				Ref.view.gameScene.showHandHit();
				Ref.model.powerLevel = 0.0;
				
				// HAND HIT VERIFICATION ///////////////////////////////////////////
				var hitItem:Sprite;
				var hitItemIndex:int;
				Ref.view.gameScene.debug.graphics.clear();
				for ( var i:int = 0; i < Ref.view.stripItems.length ; i++)
				{
					var item:Sprite = Ref.view.stripItems[i] as Sprite;
					var _y:Number   = item.y; 
					var _x:Number   = item.x;
					
					/*Ref.view.gameScene.debug.graphics.lineStyle(1,0xff0000);
					Ref.view.gameScene.debug.graphics.drawRect(_x - item.width/2.0, _y , item.width,item.height);
					Ref.view.gameScene.debug.graphics.beginFill(0);
					Ref.view.gameScene.debug.graphics.drawCircle(  handPosition.x, handPosition.y, 3);
					Ref.view.gameScene.debug.graphics.endFill();
*/
					if ( _x - item.width/2.0 < handPosition.x && _x + item.width/2.0 > handPosition.x && 
						_y  < handPosition.y && _y + item.height > handPosition.y )
					{ 
						hitItem      = item;
						hitItemIndex = i;
						
						trace("Le pegue a un item !! " + hitItemIndex);
						break;
					}
				}
				
				if ( hitItem != null )
				{
					Ref.view.gameScene.hitItem( hitItem , hitItemIndex);
				}
			}
			else if ( Input.mouseDown )
			{
				Ref.view.gameScene.showHandPrepared();
				Ref.model.powerLevel += Ref.model.powerLevelSpeed;
				Ref.model.powerLevel = Math.min(1.0,Ref.model.powerLevel);
			}
			else
				Ref.view.gameScene.showHandIdle();

			Ref.view.gameScene.updatePowerMeter();
		} 
		
		protected function processPhysicCollitions():void
		{
			
		}
		
		protected function removeExtraItems():void
		{
			Ref.view.gameScene.removeExtraItems();
		}

		protected function createItem():void
		{
			if ( !Ref.view.stripItems ) return;
			if ( Ref.view.stripItems.length > 0 ) 
			{
				var lastItem:DisplayObject = Ref.view.stripItems[Ref.view.stripItems.length-1];
				if ( Ref.model.screenWidth - (lastItem.x + lastItem.width/2.0 ) < Ref.model.itemCreationGap ) return;
	
				Ref.view.gameScene.createNewItem();
			}
			else
				Ref.view.gameScene.createNewItem();
		}

		protected function createEnemy():void
		{
			if (  Ref.model.gameTimeTicks % int(Ref.model.enemyCreationSpeed) != 0 ) return;
			if ( Ref.view.enemies.length > 5 ) return;
			Ref.view.gameScene.createNewEnemy();
		}
	}
}